package com.knife.cachev2.infra.init;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.knife.redis.KnifeRedisHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * redis缓存模板类，简单缓存，字符串 kev-value形式
 *
 * @author lth
 * @created 2025年07月28日 星期一 16:09
 */
@SuppressWarnings("ALL")
@Slf4j
public class SimpleRedisCacheTemplate<T> implements RedisCacheInitiator {

    /**
     * 缓存的键前缀
     */
    private String prefix;

    /**
     * 缓存数据
     */
    private Supplier<List<T>> cacheDataSupplier;

    /**
     * 缓存的键
     */
    private Function<T, String> keySupplier;

    /**
     * 缓存放入的数据库
     */
    private int db;

    /**
     * redis操作
     */
    private KnifeRedisHelper knifeRedisHelper;

    /**
     * mapper序列化
     */
    private ObjectMapper objectMapper;

    public SimpleRedisCacheTemplate(int db,
                                    String prefix,
                                    Supplier<List<T>> cacheDataSupplier,
                                    Function<T, String> keySupplier,
                                    KnifeRedisHelper knifeRedisHelper,
                                    ObjectMapper objectMapper
    ) {
        this.cacheDataSupplier = cacheDataSupplier;
        this.keySupplier = keySupplier;
        this.db = db;
        this.prefix = prefix;
        this.knifeRedisHelper = knifeRedisHelper;
        this.objectMapper = objectMapper;
    }


    /**
     * 读取缓存
     *
     * @param param 参数
     * @return 缓存
     */
    public T getCache(T param) {
        String key = keySupplier.apply(param);
        if (StringUtils.isEmpty(key)) {
            log.warn("未找到缓存键值");
            return null;
        }
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            return knifeRedisHelper.strGet(prefix + ":" + key, (Class<T>) param.getClass());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }

    /**
     * 设置缓存
     *
     * @param cacheObj 缓存对象
     */
    public void setCache(T cacheObj) {
        String key = keySupplier.apply(cacheObj);
        if (StringUtils.isEmpty(key)) {
            log.warn("未找到缓存键值");
            return;
        }
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            knifeRedisHelper.strSet(prefix + ":" + key, objectMapper.writeValueAsString(cacheObj));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }

    /**
     * 删除缓存
     *
     * @param cacheObj 包含key
     */
    public void deleteCache(T cacheObj){
        String key = keySupplier.apply(cacheObj);
        if (StringUtils.isEmpty(key)) {
            log.warn("未找到缓存键值");
            return;
        }
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            knifeRedisHelper.delKey(prefix + ":" + key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }

    /**
     * 缓存集合
     *
     * @param list 待缓存数据
     */
    private void cacheList(List<T> list) {
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            for (T t : list) {
                String key = keySupplier.apply(t);
                if (StringUtils.isEmpty(key)) {
                    log.warn("未找到缓存键值");
                    continue;
                }
                knifeRedisHelper.strSet(prefix + ":" + key, objectMapper.writeValueAsString(t));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }

    @Override
    public void init() {
        List<T> list = cacheDataSupplier.get();
        cacheList(list);
    }

    /**
     * 初始化指定的数据，用于对部分数据批量删除之后，重新加载缓存
     *
     * @param cacheDataSupplier 提供数据
     */
    public void initOrderData(Supplier<List<T>> cacheDataSupplier) {
        List<T> list = cacheDataSupplier.get();
        cacheList(list);
    }

    @Override
    public void clear() {
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            Set<String> keys = knifeRedisHelper.getRedisTemplate().keys(prefix+"*");
            if (Objects.nonNull(keys)) {
                knifeRedisHelper.getRedisTemplate().delete(keys);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }
}
